home *** CD-ROM | disk | FTP | other *** search
/ Visual Cafe 3 / Visual Cafe 3.ISO / Vcafe / JFC.bin / BasicTableUI.java < prev    next >
Text File  |  1998-06-30  |  26KB  |  766 lines

  1. /*
  2.  * @(#)BasicTableUI.java    1.49 98/04/09
  3.  *
  4.  * Copyright (c) 1997 Sun Microsystems, Inc. All Rights Reserved.
  5.  *
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  *
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  *
  19.  */
  20.  
  21. package com.sun.java.swing.plaf.basic;
  22.  
  23. import com.sun.java.swing.table.*;
  24. import com.sun.java.swing.*;
  25. import com.sun.java.swing.event.*;
  26. import java.util.Enumeration;
  27. import java.awt.event.*;
  28. import java.awt.*;
  29. import com.sun.java.swing.plaf.*;
  30. import java.io.Serializable;
  31. import java.util.EventObject;
  32.  
  33. import com.sun.java.swing.text.*;
  34.  
  35. /**
  36.  * BasicTableUI implementation
  37.  * <p>
  38.  * Warning: serialized objects of this class will not be compatible with
  39.  * future swing releases.  The current serialization support is appropriate
  40.  * for short term storage or RMI between Swing1.0 applications.  It will
  41.  * not be possible to load serialized Swing1.0 objects with future releases
  42.  * of Swing.  The JDK1.2 release of Swing will be the compatibility
  43.  * baseline for the serialized form of Swing objects.
  44.  *
  45.  * @version 1.49 04/09/98
  46.  * @author Philip Milne
  47.  * @author Alan Chung
  48.  */
  49. public class BasicTableUI extends TableUI implements MouseListener,
  50.     MouseMotionListener, FocusListener, Serializable
  51. {
  52.  
  53. //
  54. // Instance Variables
  55. //
  56.  
  57.     /** The JTable this UI is hooked up to */
  58.     protected JTable table;
  59.  
  60.     // PENDING(philip): Workaround for mousePressed bug in AWT 1.1
  61.     private boolean phantomMousePressed = false;
  62.  
  63.     private KeyListener tableKeyListener;
  64.  
  65.     /** Component that will recieve mouse events while editing. Not
  66.      * necessarily the editorComponent. */
  67.     transient protected Component dispatchComponent;
  68.     protected CellRendererPane rendererPane;
  69.  
  70. //
  71. // Install/Deinstall UI
  72. //
  73.  
  74.    // An anonymous inner class would be better here, but we want to
  75.    // keep all the methods this calls (eg. moveAnchor) private -
  76.    // as this part of the implementation is likely to change.
  77.    private class ArrowKeyAction extends AbstractAction implements Serializable {
  78.         transient protected int dx;
  79.         transient protected int dy;
  80.  
  81.         public ArrowKeyAction(int dx, int dy) {
  82.             this.dx = dx;
  83.             this.dy = dy;
  84.         }
  85.  
  86.         public boolean inRange(int index, int max) { return index >= 0 && index < max; }
  87.  
  88.         public void actionPerformed(ActionEvent e) {
  89.             int anchorColumn = table.getSelectedColumn() + dx;
  90.             if (!inRange(anchorColumn, table.getColumnCount())) {
  91.                  return;
  92.             }
  93.             int anchorRow = table.getSelectedRow() + dy;
  94.             if (!inRange(anchorRow, table.getRowCount())) {
  95.                  return;
  96.             }
  97.         if (dx != 0) {
  98.              clearSelection(table.getColumnModel().getSelectionModel());
  99.         }
  100.         if (dy != 0) {
  101.              clearSelection(table.getSelectionModel());
  102.         }
  103.         moveAnchor(anchorRow, anchorColumn);
  104.         }
  105.     }
  106.  
  107.     private void registerArrowKey(int keyEvent, int dx, int dy) {
  108.         table.registerKeyboardAction(new ArrowKeyAction(dx, dy),
  109.                         KeyStroke.getKeyStroke(keyEvent, 0), JComponent.WHEN_FOCUSED);
  110.     }
  111.  
  112.     private void registerKeyboardActions()
  113.     {
  114.         registerArrowKey(KeyEvent.VK_RIGHT,  1,  0);
  115.         registerArrowKey(KeyEvent.VK_LEFT , -1,  0);
  116.         registerArrowKey(KeyEvent.VK_UP,     0, -1);
  117.         registerArrowKey(KeyEvent.VK_DOWN ,  0,  1);
  118.  
  119.         tableKeyListener = new TableKeyListener();
  120.         table.addKeyListener(tableKeyListener);
  121.  
  122.     }
  123.  
  124.     private void unregisterKeyboardActions() {
  125.         table.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0));
  126.         table.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0));
  127.         table.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0));
  128.         table.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0));
  129.         table.removeKeyListener(tableKeyListener);
  130.     }
  131.  
  132.     private void moveAnchor(int row, int column) {
  133.     if (table.isEditing()) {
  134.         TableCellEditor cellEditor = table.getCellEditor();
  135.         // Try to stop the current editor
  136.         if (cellEditor != null) {
  137.         boolean stopped = cellEditor.stopCellEditing();
  138.         if (!stopped)
  139.             return;    // The current editor not resigning
  140.         }
  141.     }
  142.     updateSelection(row, column, false, true);
  143.     }
  144.  
  145.     private class TableKeyListener implements KeyListener, Serializable
  146.     {
  147.         public void keyPressed(KeyEvent e) {
  148.         switch (e.getKeyCode()) {
  149.             case KeyEvent.VK_UP:
  150.                 break;
  151.             case KeyEvent.VK_DOWN:
  152.                 break;
  153.             case KeyEvent.VK_LEFT:
  154.                 break;
  155.             case KeyEvent.VK_RIGHT:
  156.                 break;
  157.             case KeyEvent.VK_SHIFT:
  158.                 break;
  159.             case KeyEvent.VK_CONTROL:
  160.                 break;
  161.             default:
  162.                     dispatchKeyboardEvent(e);
  163.                     break;
  164.             }
  165.         }
  166.  
  167.         public void keyReleased(KeyEvent e) { }
  168.         public void keyTyped(KeyEvent e) { }
  169.     }
  170.  
  171.     private void dispatchKeyboardEvent(KeyEvent e) {
  172.         int selectedRow = table.getSelectedRow();
  173.         int selectedColumn = table.getSelectedColumn();
  174.     if (selectedRow != -1 && selectedColumn != -1 && !table.isEditing()) {
  175.         boolean editing = table.editCellAt(selectedRow, selectedColumn);
  176.             table.requestFocus();
  177.         if (!editing) {
  178.             return;
  179.         }
  180.     }
  181.  
  182.         Component editorComp = table.getEditorComponent();
  183.         if (table.isEditing() && editorComp != null) {
  184.  // Have to give the textField the focus temporarily so
  185.  // that it can perform the action.
  186.             char keyChar = e.getKeyChar();
  187.             if (editorComp instanceof JTextField) {
  188.                 JTextField textField = (JTextField)editorComp;
  189.                 Keymap keyMap = textField.getKeymap();
  190.                 KeyStroke key = KeyStroke.getKeyStroke(keyChar, 0);
  191.                 Action action = keyMap.getAction(key);
  192.                 if (action == null) {
  193.                     action = keyMap.getDefaultAction();
  194.                 }
  195.         if (action != null) {
  196.             ActionEvent ae = new ActionEvent(textField,
  197.                              ActionEvent.ACTION_PERFORMED,
  198.                              String.valueOf(keyChar));
  199.             action.actionPerformed(ae);
  200. //            e.consume();
  201.         }
  202.            }
  203.         }
  204.     }
  205.  
  206.     /**
  207.      * Initialize JTable properties, e.g. font, foreground, and background.
  208.      * The font, foreground, and background
  209.      * properties are only set if their current value is either null
  210.      * or a UIResource, other properties are set if the current
  211.      * value is null.
  212.      *
  213.      * @see #installUI
  214.      */
  215.     private void configureTable()
  216.     {
  217.       // list.setLayout(null);
  218.         LookAndFeel.installColorsAndFont(table, "Table.background",
  219.                      "Table.foreground", "Table.font");
  220.  
  221.         Color sbg = table.getSelectionBackground();
  222.     if (sbg == null || sbg instanceof UIResource) {
  223.         table.setSelectionBackground(UIManager.getColor("Table.selectionBackground"));
  224.     }
  225.  
  226.         Color sfg = table.getSelectionForeground();
  227.     if (sfg == null || sfg instanceof UIResource) {
  228.         table.setSelectionForeground(UIManager.getColor("Table.selectionForeground"));
  229.     }
  230.  
  231.         Color gridColor = table.getGridColor();
  232.     if (gridColor == null || gridColor instanceof UIResource) {
  233.         table.setGridColor(UIManager.getColor("Table.gridColor"));
  234.     }
  235.  
  236.     // install the scrollpane border
  237.     Container parent = table.getParent();  // should be viewport
  238.     if (parent != null) {
  239.         parent = parent.getParent();  // should be the scrollpane
  240.         if (parent != null && parent instanceof JScrollPane) {
  241.             LookAndFeel.installBorder((JScrollPane)parent, "Table.scrollPaneBorder");
  242.         }
  243.     }
  244.  
  245.     }
  246.  
  247.     public static ComponentUI createUI(JComponent c) {
  248.         return new BasicTableUI();
  249.     }
  250.  
  251.     public void installUI(JComponent c) {
  252.     table = (JTable)c;
  253.  
  254.     c.addMouseListener(this);
  255.         c.addMouseMotionListener(this);
  256.     c.addFocusListener(this);
  257.  
  258.     rendererPane = new CellRendererPane();
  259.     table.add(rendererPane);
  260.  
  261.     configureTable();
  262.         registerKeyboardActions();
  263.     }
  264.  
  265.     public void uninstallUI(JComponent c) {
  266.     table.remove(rendererPane);
  267.  
  268.     c.removeMouseListener(this);
  269.         c.removeMouseMotionListener(this);
  270.     c.removeFocusListener(this);
  271.  
  272.     unregisterKeyboardActions();
  273.  
  274.     rendererPane = null;
  275.     table = null;
  276.     }
  277.  
  278. //
  279. // MouseListener, MouseMotionListener, FocusListener Methods
  280. //
  281.  
  282.     private void repaintAnchorCell() {
  283.         int anchorRow = table.getSelectedRow();
  284.         int anchorColumn = table.getSelectedColumn();
  285.         Rectangle dirtyRect = table.getCellRect(anchorRow, anchorColumn, false);
  286.         table.repaint(dirtyRect);
  287.     }
  288.  
  289.     public void focusGained(FocusEvent e) {
  290.         if (table.getSelectedColumn() == -1) {
  291.             table.setColumnSelectionInterval(0, 0);
  292.         }
  293.         if (table.getSelectedRow() == -1) {
  294.             table.setRowSelectionInterval(0, 0);
  295.         }
  296.         repaintAnchorCell();
  297.     }
  298.  
  299.     public void focusLost(FocusEvent e) {
  300.         repaintAnchorCell();
  301.     }
  302.  
  303.     public void mouseMoved(MouseEvent e) {
  304.         if (dispatchComponent != null)
  305.         dispatchComponent = null;
  306.     }
  307.  
  308.     public void mouseClicked(MouseEvent e) {}
  309.  
  310.     public void mouseEntered(MouseEvent e) {
  311.         if (dispatchComponent != null)
  312.         dispatchComponent = null;
  313.     }
  314.  
  315.     public void mouseExited(MouseEvent e) {
  316.         if (dispatchComponent != null)
  317.         dispatchComponent = null;
  318.     }
  319.  
  320.     public void mousePressed(MouseEvent e) {
  321.         if (phantomMousePressed == true) {
  322.             // System.err.println("BasicTableUI recieved two consecutive mousePressed events.");
  323.             return;
  324.         }
  325.         phantomMousePressed = true;
  326.  
  327.     Point p = e.getPoint();
  328.  
  329.     int hitRowIndex = table.rowAtPoint(p);
  330.     int hitColumnIndex = table.columnAtPoint(p);
  331.     if ((hitColumnIndex == -1) || (hitRowIndex == -1)) {
  332.         // Didn't hit a valid cell
  333.         return;
  334.     }
  335.     Rectangle cellRect = table.getCellRect(hitRowIndex, hitColumnIndex, false);
  336.  
  337.     if(cellRect.contains(p)) {
  338.         table.editCellAt(hitRowIndex, hitColumnIndex, e);
  339.         }
  340.  
  341.     if(!table.isEditing()) {
  342.         table.requestFocus();
  343.  
  344.         // We hit the margin around a cell, or the cell hit didn't start
  345.         // the editor.  So we can now handle it as a selection click.
  346.         boolean controlKeyDown = e.isControlDown();
  347.         boolean shiftKeyDown = e.isShiftDown();
  348.         boolean deselect = (controlKeyDown &&
  349.                 table.isCellSelected(hitRowIndex, hitColumnIndex));
  350.             if (!controlKeyDown && !shiftKeyDown) {
  351.                  clearSelection();
  352.         }
  353.         updateSelection(hitRowIndex, hitColumnIndex, deselect, !shiftKeyDown || deselect);
  354.     }
  355.     else {
  356.         Component      editorComp = table.getEditorComponent();
  357.         Point          componentPoint = SwingUtilities.convertPoint
  358.         (table, new Point(e.getX(), e.getY()), editorComp);
  359.  
  360.         dispatchComponent = SwingUtilities.getDeepestComponentAt
  361.         (editorComp, componentPoint.x, componentPoint.y);
  362.         dispatchComponent.dispatchEvent(SwingUtilities.convertMouseEvent
  363.                       (table, e, dispatchComponent));
  364.     }
  365.     }
  366.  
  367.     public void mouseDragged(MouseEvent e) {
  368.     if (table.isEditing()) {
  369.         if(dispatchComponent != null)
  370.         dispatchComponent.dispatchEvent
  371.             (SwingUtilities.convertMouseEvent(table, e,
  372.                               dispatchComponent));
  373.         return;
  374.     }
  375.  
  376.     Point p = e.getPoint();
  377.     int hitRowIndex = table.rowAtPoint(p);
  378.     int hitColumnIndex = table.columnAtPoint(p);
  379.     if ((hitColumnIndex == -1) || (hitRowIndex == -1)) {
  380.         // Didn't hit a valid cell
  381.         return;
  382.     }
  383.     updateSelection(hitRowIndex, hitColumnIndex, false, false);
  384.     }
  385.  
  386.     public void mouseReleased(MouseEvent e) {
  387.         phantomMousePressed = false;
  388.     if (table.isEditing()) {
  389.         if (dispatchComponent != null)
  390.         dispatchComponent.dispatchEvent
  391.             (SwingUtilities.convertMouseEvent(table, e,
  392.                               dispatchComponent));
  393.         dispatchComponent = null;
  394.         return;
  395.     }
  396.     // Finish and clean-up from selection
  397.     }
  398.  
  399. //
  400. // Paint Methods and support
  401. //
  402.  
  403.     public void paint(Graphics g, JComponent c) {
  404.         JTable table = (JTable) c;
  405.     Rectangle paintBounds = g.getClipBounds();
  406.         Dimension size = table.getSize();
  407.  
  408.     if (table.getColumnModel() == null)
  409.         // Can't draw if I don't have a columnModel
  410.         return;
  411.  
  412.     // Paint the background first
  413.     Dimension pSize = getPreferredSize(table);
  414.     Rectangle tableRect = new Rectangle(0,0,pSize.width,pSize.height);
  415.     tableRect = tableRect.intersection(paintBounds);
  416.  
  417.         g.setColor(table.getParent().getBackground());
  418.         /*
  419.         // Don't repaint the whole background, only to cover it with white
  420.         // below. This causes awful flickering when scrolling if
  421.         // double buffering is turned off.
  422.         Rectangle bg[] = SwingUtilities.computeDifference(paintBounds, tableRect);
  423.         for(int i = 0; i < bg.length; i++) {
  424.         g.fillRect(bg[i].x, bg[i].y, bg[i].width, bg[i].height);
  425.         }
  426.         */
  427.         // This caused a refresh bug, fill the whole region for now - revisit this.
  428.         g.fillRect(paintBounds.x, paintBounds.y, paintBounds.width, paintBounds.height);
  429.  
  430.         // The height and width of the dirty region can somehow be negative.
  431.         // Check for this and return as this odd line segments to be drawn
  432.         // during the refreshing of the part of the display that should have
  433.         // been painted in the viewport background color when the table is smaller
  434.         // than the view.
  435.         // PENDING(philip): Ensure that these dimensions are positive in the first place.
  436.     if (tableRect.height < 0 || tableRect.width < 0) {
  437.             return;
  438.     }
  439.  
  440.     Color bColor = table.getBackground();
  441.     if(bColor != null) {
  442.         g.setColor(bColor);
  443.         g.fillRect(tableRect.x, tableRect.y, tableRect.width, tableRect.height);
  444.     }
  445.  
  446.     // Next draw the grid
  447.     drawGridInClipRect(tableRect, g);
  448.  
  449.     // Finally draw the rows
  450.     int index;
  451.     Rectangle rowRect, intersection;
  452.  
  453.         Rectangle r = g.getClipBounds();
  454.         int firstIndex = table.rowAtPoint(new Point(0, r.y));
  455.         int  lastIndex = lastVisibleRow(r);
  456.  
  457.         rowRect = new Rectangle(0, 0,
  458.                    table.getColumnModel().getTotalColumnWidth(),
  459.            table.getRowHeight() + table.getIntercellSpacing().height);
  460.         rowRect.y = firstIndex*rowRect.height;
  461.  
  462.     for (index = firstIndex; index <= lastIndex; index++) {
  463.         // draw any rows that need to be drawn
  464.         if (rowRect.intersects(tableRect)) {
  465.         intersection = rowRect.intersection(tableRect);
  466.         this.drawRowInClipRect(index, intersection, g);
  467.         }
  468.         rowRect.y += rowRect.height;
  469.     }
  470.     }
  471.  
  472. //
  473. // Size Methods
  474. //
  475.  
  476.     public Dimension getMinimumSize(JComponent c) {
  477.         return getPreferredSize(c);
  478.     }
  479.  
  480.   /**  If the table is autoresizing its columns
  481.     *  <code>(getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)</code>
  482.     *  and the JTable is also inside a scrollpane, the preferred width
  483.     *  of the JTable is the width of the viewport that contains it.
  484.     *  Otherwise, the preferred width is the total width of all
  485.     *  of the columns. The preferred height it the number of rows
  486.     *  times the preferred height (including the intercell spacing).
  487.     *  <p>
  488.     *  The result is that when the mode of the JTable is AUTO_RESIZE_OFF
  489.     *  columns are not autoresized and a horizontal scrollbar appears
  490.     *  when the total width of the columns excedes the width of the
  491.     *  JScrollPane. When the mode is not AUTO_RESIZE_OFF the JTable
  492.     *  autoresizes its columns continually to ensure that they fill
  493.     *  the full width of the JScrollPane.
  494.     */
  495.     public Dimension getPreferredSize(JComponent c) {
  496.         JTable table = (JTable)c;
  497.         Dimension size = new Dimension();
  498.         int mode = table.getAutoResizeMode();
  499.  
  500.         Component parent = table.getParent();
  501.         if (mode != JTable.AUTO_RESIZE_OFF && parent instanceof JViewport) {
  502.             size.width = parent.getBounds().width;
  503.             table.sizeColumnsToFit(mode == JTable.AUTO_RESIZE_LAST_COLUMN);
  504.         }
  505.         else {
  506.             size.width = table.getColumnModel().getTotalColumnWidth();
  507.         }
  508.         size.height = table.getRowCount() * (table.getRowHeight() +
  509.                       table.getIntercellSpacing().height);
  510.         return size;
  511.     }
  512.  
  513.     public Dimension getMaximumSize(JComponent c) {
  514.         return getPreferredSize(c);
  515.     }
  516.  
  517. //
  518. // Protected & Private Methods
  519. //
  520.  
  521.     private int lastVisibleRow(Rectangle clipRect) {
  522.         int lastIndex = table.rowAtPoint(new Point(0, clipRect.y + clipRect.height - 1));
  523.         // If the table does not have enough rows to fill the view we'll get -1.
  524.         // Replace this with the index of the last row.
  525.         if (lastIndex == -1) {
  526.                 lastIndex = table.getRowCount() -1;
  527.         }
  528.         return lastIndex;
  529.     }
  530.  
  531.     /**
  532.      * Draws the grid lines within <I>aRect</I>, using the grid
  533.      * color set with <I>setGridColor</I>. Draws vertical lines
  534.      * if <code>getShowVerticalLines()</code> returns true and draws
  535.      * horizontal lines if <code>getShowHorizontalLines()</code>
  536.      * returns true.
  537.      */
  538.     protected void drawGridInClipRect(Rectangle rect, Graphics g) {
  539.     g.setColor(table.getGridColor());
  540.  
  541.         if (table.getShowHorizontalLines()) {
  542.             drawHorizontalLinesInClipRect(rect, g);
  543.         }
  544.         if (table.getShowVerticalLines()) {
  545.             drawVerticalLinesInClipRect(rect, g);
  546.         }
  547.     }
  548.  
  549.     /**
  550.      * This method draws horizontal lines regardless of whether the
  551.      * table is set to draw one automatically.
  552.      * Subclasses can override this method to draw grid lines
  553.      * other than the standard ones.
  554.      */
  555.     protected void drawHorizontalLinesInClipRect(Rectangle rect, Graphics g) {
  556.     int delta = table.getRowHeight() + table.getIntercellSpacing().height;
  557.         Rectangle r = g.getClipBounds();
  558.         int firstIndex = table.rowAtPoint(new Point(0, r.y));
  559.         int  lastIndex = lastVisibleRow(r);
  560.         int y = delta*firstIndex+(delta-1);
  561.  
  562.     for (int index = firstIndex; index <= lastIndex; index ++) {
  563.         if ((y >= rect.y) && (y <= (rect.y + rect.height))) {
  564.         g.drawLine(rect.x, y, rect.x + rect.width - 1, y);
  565.         }
  566.         y += delta;
  567.     }
  568.     }
  569.  
  570.     /**
  571.      * This method draws vertical lines regardless of whether the
  572.      * table is set to draw one automatically.
  573.      * Subclasses can override this method to draw grid lines
  574.      * other than the standard ones.
  575.      */
  576.     protected void drawVerticalLinesInClipRect(Rectangle rect, Graphics g) {
  577.     int x = 0;
  578.     int count = table.getColumnCount();
  579.     for (int index = 0; index <= count; index ++) {
  580.         if ((x > 0) && (((x-1) >= rect.x) && ((x-1) <= (rect.x + rect.width)))){
  581.         g.drawLine(x - 1, rect.y, x - 1, rect.y + rect.height - 1);
  582.         }
  583.  
  584.         if (index < count)
  585.         x += ((TableColumn)table.getColumnModel().getColumn(index)).
  586.             getWidth() + table.getIntercellSpacing().width;
  587.     }
  588.     }
  589.  
  590.     /**
  591.      * Draws the cells for the row at rowIndex in the columns that intersect
  592.      * clipRect.  Subclasses can override this method to customize their appearance.
  593.      */
  594.     protected void drawRowInClipRect(int row, Rectangle rect, Graphics g) {
  595.     int column = 0;
  596.     boolean drawn = false;
  597.     Rectangle cellRect, draggedCellRect = null;
  598.     TableColumn aColumn;
  599.     int draggedColumnIndex = -1;
  600.     TableCellRenderer renderer;
  601.     Enumeration enumeration = table.getColumnModel().getColumns();
  602.     Dimension spacing = table.getIntercellSpacing();
  603.     JTableHeader header = table.getTableHeader();
  604.  
  605.     // Set up the cellRect
  606.     cellRect = new Rectangle();
  607.     cellRect.height = table.getRowHeight() + spacing.height;
  608.     cellRect.y = row * cellRect.height;
  609.  
  610.     // Paint the non-dragged table cells first
  611.     while (enumeration.hasMoreElements()) {
  612.         aColumn = (TableColumn)enumeration.nextElement();
  613.  
  614.         cellRect.width = aColumn.getWidth() + spacing.width;
  615.         if (cellRect.intersects(rect)) {
  616.         drawn = true;
  617.         if ((header == null) || (aColumn != header.getDraggedColumn())) {
  618.             renderer = getCellRenderer(column);
  619.             Component component = prepareRenderer(renderer, table, row, column);
  620.             drawWithComponent(g, component, cellRect);
  621.         }
  622.         else {
  623.             // Draw a gray well in place of the moving column
  624.             g.setColor(table.getParent().getBackground());
  625.             g.fillRect(cellRect.x, cellRect.y,
  626.                    cellRect.width, cellRect.height);
  627.             draggedCellRect = new Rectangle(cellRect);
  628.             draggedColumnIndex = column;
  629.         }
  630.         }
  631.         else {
  632.         if (drawn)
  633.             // Don't need to iterate through the rest
  634.             break;
  635.         }
  636.  
  637.         cellRect.x += cellRect.width;
  638.         column++;
  639.     }
  640.  
  641.     // draw the dragged cell if we are dragging
  642.     if (draggedColumnIndex != -1 && draggedCellRect != null) {
  643.         renderer = getCellRenderer(draggedColumnIndex);
  644.         if (renderer != null) {
  645.         Component component = prepareRenderer(renderer, table,
  646.                               row, draggedColumnIndex);
  647.         draggedCellRect.x += header.getDraggedDistance();
  648.         // Fill the background then draw a complete grid if required
  649.         Color bColor = table.getBackground();
  650.         if (bColor != null) {
  651.             g.setColor(bColor);
  652.             g.fillRect(draggedCellRect.x, draggedCellRect.y,
  653.                    draggedCellRect.width, draggedCellRect.height);
  654.         }
  655.  
  656.         // Draw grid if necessary.
  657.         g.setColor(table.getGridColor());
  658.         int x1 = draggedCellRect.x;
  659.         int y1 = draggedCellRect.y;
  660.         int x2 = x1 + draggedCellRect.width - 1;
  661.         int y2 = y1 + draggedCellRect.height - 1;
  662.         // Right
  663.         if (table.getShowVerticalLines()) {
  664.             g.drawLine(x2, y1, x2, y2);
  665.         }
  666.         // Bottom
  667.         if (table.getShowHorizontalLines()) {
  668.             g.drawLine(x1, y2, x2, y2);
  669.         }
  670.         drawWithComponent(g, component, draggedCellRect);
  671.         }
  672.     }
  673.     }
  674.  
  675.     protected TableCellRenderer getCellRenderer(int column) {
  676.         TableColumn tableColumn = table.getColumnModel().getColumn(column);
  677.         TableCellRenderer renderer = tableColumn.getCellRenderer();
  678.         if (renderer == null) {
  679.             Class columnClass = table.getColumnClass(column);
  680.             renderer = table.getDefaultRenderer(columnClass);
  681.         }
  682.         return renderer;
  683.     }
  684.  
  685.     protected Component prepareRenderer(TableCellRenderer renderer,
  686.                     JTable table, int row, int column) {
  687.         Object value = table.getValueAt(row, column);
  688.     boolean isSelected = table.isCellSelected(row, column);
  689.     boolean rowIsAnchor = (table.getSelectedRow() == row);
  690.     boolean columnIsAnchor = (table.getSelectedColumn() == column);
  691.     boolean hasFocus = (rowIsAnchor && columnIsAnchor) && table.hasFocus();
  692.  
  693.     return renderer.getTableCellRendererComponent(table, value,
  694.                                                   isSelected, hasFocus,
  695.                                                   row, column);
  696.     }
  697.  
  698.     protected void drawWithComponent(Graphics g, Component component,
  699.                                                         Rectangle cellRect) {
  700.     // The cellRect is inset by half the intercellSpacing before drawn
  701.     Dimension spacing = table.getIntercellSpacing();
  702.     // Round so that when the spacing is 1 the cell does not draw obscure lines.
  703.         cellRect.setBounds(cellRect.x + spacing.width/2, cellRect.y + spacing.height/2,
  704.                            cellRect.width - spacing.width, cellRect.height - spacing.height);
  705.  
  706.         if (component.getParent() == null) {
  707.             rendererPane.add(component);
  708.         }
  709.     rendererPane.paintComponent(g, component, table, cellRect.x, cellRect.y,
  710.                                     cellRect.width, cellRect.height, true);
  711.     // Have to restore the cellRect back to it's orginial size
  712.         cellRect.setBounds(cellRect.x - spacing.width/2, cellRect.y - spacing.height/2,
  713.                            cellRect.width + spacing.width, cellRect.height + spacing.height);
  714.  
  715.     }
  716.  
  717.  
  718.     private void updateSelectionModel(ListSelectionModel sm, int index,
  719.                                       boolean deselect, boolean reAnchor) {
  720.         if (reAnchor) {
  721.             if (!deselect) {
  722.                 sm.addSelectionInterval(index, index);
  723.             }
  724.             else {
  725.                 sm.removeSelectionInterval(index, index);
  726.                 // sm.setAnchorSelectionIndex(index);
  727.                 return;
  728.             }
  729.         }
  730.  
  731.         sm.setLeadSelectionIndex(index);
  732.     }
  733.  
  734.  
  735.     private void updateSelection(int rowIndex, int columnIndex,
  736.                                    boolean deselect, boolean reAnchor) {
  737.         // Autoscrolling support.
  738.     Rectangle cellRect = table.getCellRect(rowIndex, columnIndex, false);
  739.         if (cellRect != null) {
  740.         table.scrollRectToVisible(cellRect);
  741.         }
  742.  
  743.         ListSelectionModel rsm = table.getSelectionModel();
  744.         ListSelectionModel csm = table.getColumnModel().getSelectionModel();
  745.  
  746.     // Update column selection model
  747.     updateSelectionModel(csm, columnIndex, deselect, reAnchor);
  748.  
  749.     // Update row selection model
  750.     updateSelectionModel(rsm, rowIndex, deselect, reAnchor);
  751.     }
  752.  
  753.     // Its faster to deselect, rather than clear.
  754.     private void clearSelection() {
  755.         clearSelection(table.getColumnModel().getSelectionModel());
  756.         clearSelection(table.getSelectionModel());
  757.     }
  758.  
  759.     // Its faster to deselect, rather than clear.
  760.     private void clearSelection(ListSelectionModel sm) {
  761.         sm.removeSelectionInterval(sm.getMinSelectionIndex(), sm.getMaxSelectionIndex());
  762.     }
  763.  
  764. }  // End of Class BasicTableUI
  765.  
  766.